package bma.common.langutil.concurrent;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import junit.framework.TestCase;
import bma.common.langutil.core.LruCache;
import bma.common.langutil.core.ObjectUtil;

public class LruCacheTC extends TestCase {

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(LruCacheTC.class);

	public void testBase() throws Exception {
		LruCache<Integer, Integer> c = new LruCache<Integer, Integer>(8);		
		for (int i = 0; i < 11; i++) {
			c.put(i, i);
		}
		log.info("cache = {}", c.snapshot());
		// log.info("check = {}", c.checkInnerData());
	}

	public void testMutilThread() throws Exception {

		ExecutorService e = Executors.newCachedThreadPool();
		final int cacheSize = 10;
		final LruCache<Integer, Boolean> m1 = new LruCache<Integer, Boolean>(
				cacheSize);
		final Map<Integer, Boolean> m2 = Collections
				.synchronizedMap(new LinkedHashMap<Integer, Boolean>(
						cacheSize * 2) {
					@Override
					protected boolean removeEldestEntry(
							java.util.Map.Entry<Integer, Boolean> eldest) {
						return size() > cacheSize;
					}
				});
		final boolean testCache = true;
		final int threads = 100;
		boolean read = false;
		boolean write = true;

		log.info("start");
		long start = System.currentTimeMillis();

		List<Callable<Integer>> list = new ArrayList<Callable<Integer>>();
		for (int i = 0; i < threads; i++) {
			final int j = i;
			Callable<Integer> w = new Callable<Integer>() {

				@Override
				public Integer call() throws Exception {
					Random o = new Random();
					for (int i = 0; i < 10000; i++) {
						int k = o.nextInt(1000000);
						if (testCache) {
							m1.put(k, true);
						} else {
							m2.put(k, true);
						}
					}
					return j;
				}
			};
			Callable<Integer> r = new Callable<Integer>() {

				@Override
				public Integer call() throws Exception {
					Random o = new Random();
					for (int i = 0; i < 10000 * 2; i++) {
						int k = o.nextInt(1000000);
						if (testCache) {
							m1.get(k);
						} else {
							m2.get(k);
						}
					}
					return j;
				}
			};
			if (write) {
				list.add(w);
			}
			if (read) {
				list.add(r);
			}
		}
		List l = e.invokeAll(list);

		log.info("end {}", System.currentTimeMillis() - start);
		// log.info("cache = {}", testCache ? m1.snapshot() : m2);
		// log.info("check = {}", testCache ? m1.checkInnerData() : true);
	}

	public void testTimeout() throws Exception {
		LruCache<Integer, Integer> c = new LruCache.Expire<Integer, Integer>(10, 1000);
		for (int i = 0; i < 11; i++) {
			c.put(i, i);
			ObjectUtil.waitFor(this, 100);
		}
		ObjectUtil.waitFor(this, 500);
		for (int i = 0; i < 11; i++) {
			log.info("{} => {}", i, c.get(i));
		}
	}
}
